//=============================================================================
///	String
//=============================================================================

#include "sstring.h"
#include "smem.h"
#include "sstream.h"
#include <string.h>


//=============================================================================
// String

static void str_write(SExp s, SExp strm, int escape) {
	String* p = &s.ptr->string;
	if (!escape) {
		write_cstr(p->str, strm);
	} else {
		unsigned char buf[256];
		unsigned char* last = buf + (256-4);
		unsigned char* q;
		const unsigned char* r;
		int i, l = p->len;

		q = buf;
		*q++ = '"';
		for (r=(const unsigned char*)p->str, i=0; i<l; ++i) {
			int c = *r++;
			if (c < ' ') {
				switch (c) {
				default:	sprintf(q, "\\%02x", c); q += 4;	break;
				case '\n':	strcpy(q, "\\n"); q += 2;	break;
				case '\t':	strcpy(q, "\\t"); q += 2;	break;
				case '\0':	strcpy(q, "\\0"); q += 2;	break;
				}
			} else {
				switch (c) {
				default:	*q++ = c;	break;
				case '"':	strcpy(q, "\\\""); q += 2;	break;
				}
			}
			if (q >= last) {
				*q = '\0';
				write_cstr(buf, strm);
				q = buf;
			}
		}
		strcpy(q, "\"");
		write_cstr(buf, strm);
	}
}

static STypeInfo str_typeinfo = {
	tString,	0,
	"string",
	NULL,
	NULL,
	NULL,
	str_write,
	NULL,
	NULL,
};


//=============================================================================

SExp gen_str(const char* str, int nbytes) {
	int l = (nbytes != -1) ? nbytes : strlen(str);
	String* p = smalloc(sizeof(*p) + l);		// no need +1 for '\0'
	p->typeinfo= &str_typeinfo;
	p->len = l;
	memcpy(p->str, str, l);
	p->str[l] = '\0';
	return ptr2s(p);
}

SExp concat(SExp s1, SExp s2) {
	s1 = type_check(s1, tString);
	s2 = type_check(s2, tString);
	{
		String* p1 = &s1.ptr->string;
		String* p2 = &s2.ptr->string;
		char* buf = smalloc(p1->len + p2->len + 1);
		strcpy(buf, p1->str);
		strcpy(buf + p1->len, p2->str);
		return gen_str(buf, -1);
	}
}

int string_compare(SExp s1, SExp s2) {
	s1 = type_check(s1, tString);
	s2 = type_check(s2, tString);
	return strcmp(s1.ptr->string.str, s2.ptr->string.str);
}
